﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WhatsPlayingClient.Audio
{
	public class FreqBandBuilder
	{
		delegate double forward_t(double f);
		delegate double backward_t(double z);

		static double HZ_2_MEL(double f)
		{
			return 1127.0 * Math.Log(1.0 + f / 700.0);
		}

		static double MEL_2_HZ(double m)
		{
			return 700.0 * (Math.Exp(m / 1127.0) - 1.0);
		}

		static double HZ_2_ERBS(double f)
		{
			return 21.4 * Math.Log10(0.00437 * f + 1);
		}

		static double ERBS_2_HZ(double z)
		{
			return (Math.Pow(10.0, z / 21.4) - 1) / 0.00437;
		}

		static double HZ_2_BARK(double f)
		{
			return (26.81 / (1.0 + 1960.0 / f)) - 0.53;
		}

		static double BARK_2_HZ(double z)
		{
			return 1960.0 / (26.81 / (z + 0.53) - 1);
		}

		static FreqBand[] GetBands(int min_f, int max_f, int bandsNum, forward_t transform, backward_t inverse)
		{
			FreqBand[] bands = new FreqBand[bandsNum];

			double z_min = transform(min_f);
			double z_max = transform(max_f);

			double step = (z_max - z_min) / (bandsNum);
			double z = z_min;
			for (int i = 0; i < bandsNum; i++)
			{
				bands[i] = new FreqBand(inverse(z), inverse(z + step));
				z += step;
			}

			return bands;
		}

		public enum BandType
		{
			MEL, ERBS, BARK
		}

		public static FreqBand[] GetBands(int min_f, int max_f, int bandsNum, BandType type)
		{
			switch (type)
			{
				case BandType.MEL:
					return GetBands(min_f, max_f, bandsNum, new forward_t(HZ_2_MEL), new backward_t(MEL_2_HZ));
				case BandType.ERBS:
					return GetBands(min_f, max_f, bandsNum, new forward_t(HZ_2_ERBS), new backward_t(ERBS_2_HZ));
				case BandType.BARK:
					return GetBands(min_f, max_f, bandsNum, new forward_t(HZ_2_BARK), new backward_t(BARK_2_HZ));
			}

			throw new NotSupportedException();
		}
	}
}
